package cn.modoumama.excelUilt.po;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.modoumama.excelUilt.common.InitCallStyle;

public class SheetEntity extends HashMap<Integer, Entry<String, CellEntity>> {
	Logger logger = LoggerFactory.getLogger(getClass());
	
	
    private static final long serialVersionUID = 1L;
    
    /** 工作薄*/
    private Workbook workbook;
    /** 是否有带表头*/
    private String name;
    /** 是否有带表头*/
    private boolean head = false;
    /**宽度*/
    private short width = 20;
    /**行高*/
    private short height = 24;
    /**默认时间格式 m/d/yy h:mm*/
    private String dateFormat = BuiltinFormats.getBuiltinFormat(22);
    /**当页的数据内容*/
    List<?> data;
    
    
    public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public boolean isHead() {
		return head;
	}

	public void setHead(boolean head) {
		this.head = head;
	}
	
	public Entry<String, CellEntity> put(Integer key, String field) {
		return put(key, field, null, null, null, null, null);
    }
	
	public Entry<String, CellEntity> put(Integer key, String field ,String desc) {
		return put(key, field, desc, null, null, null, null);
    }
	
	public Entry<String, CellEntity> put(Integer key, String field ,Integer width) {
		return put(key, field, null, width, null, null, null);
    }
	
	public Entry<String, CellEntity> put(Integer key, String field ,String desc ,Integer width) {
		return put(key, field, desc, width, null, null, null);
    }

	public Entry<String, CellEntity> put(Integer key, String field , String desc, Integer width , String format) {
    	return put(key, field, desc, width, format, null, null);
    }
	
	public Entry<String, CellEntity> put(Integer key, String field, InitCallStyle initCallStyle) {
		return put(key, field, null, null, null, null,initCallStyle);
    }
	
	public Entry<String, CellEntity> put(Integer key, String field ,String desc, InitCallStyle initCallStyle) {
		return put(key, field, desc, null, null, null,initCallStyle);
    }
	
	public Entry<String, CellEntity> put(Integer key, String field ,Integer width, InitCallStyle initCallStyle) {
		return put(key, field, null, width, null, null,initCallStyle);
    }
	
	public Entry<String, CellEntity> put(Integer key, String field ,String desc ,Integer width, InitCallStyle initCallStyle) {
		return put(key, field, desc, width, null, null,initCallStyle);
    }

	public Entry<String, CellEntity> put(Integer key, String field , String desc, Integer width , String format, InitCallStyle initCallStyle) {
    	return put(key, field, desc, width, format, null,initCallStyle);
    }

	public Entry<String, CellEntity> put(Integer key, String field , String desc, Integer width , String format, HSSFFont font, InitCallStyle initCallStyle) {
		CellEntity cellEntry = new CellEntity(width,desc,format,font,initCallStyle);
    	Entry<String, CellEntity> entry = new MethodEntry(field, cellEntry);
    	if(StringUtils.isNotBlank(desc)){
    		setHead(true);
    	}
    	return super.put(key, entry);
    }
    
    public String getField(Integer key){
    	return get(key).getKey();
    }
    
    public String getDesc(Integer key){
    	return get(key).getValue().getDesc();
    }
    
    public void rowHead(Row row){
    	for (Integer key : keySet()) {
    		Cell cell = row.createCell(key);
			setCell(cell, getDesc(key));
    	}
    }

	@SuppressWarnings("unchecked")
	public void rowData(Row row, Object object){
		if(object != null){
			if(object.getClass().equals(Map.class)){
	    		Map<Object, Object> map = (Map<Object, Object>)object;
	    		for (Integer key : keySet()) {
	    			Cell cell = row.createCell(key);
	    			setCell(cell, map.get(get(key)));
				}
	    	}else{
	    		for (Integer key : keySet()) {
		            String fieldName = getField(key);
		            String[] fieldNames = fieldName.split("\\.");
		            PropertyDescriptor prop = null;
		            Method read = null;
		            Object value = object;
		            for (int i = 0; i < fieldNames.length; i++) {
		            	if(value ==null){
		            		break;
		            	}
		            	try {
		            		if(value instanceof Map){
		            			value = ((Map) value).get(fieldNames[i]);
		            		}else{
		            			prop = new PropertyDescriptor(fieldNames[i], value.getClass());
								read = prop.getReadMethod();
			            		value = read.invoke(value);
		            		}
						} catch (IntrospectionException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
							logger.error(e.getMessage(),e);
						}
					}
	                try {
						Cell cell = row.createCell(key);
						setCell(cell, value);
					} catch (Exception e) {
						e.printStackTrace();
					}
	    		}
	    	}
		}
    }
    
    public void setCell(Cell cell,Object value){
    	Integer type = isPrimitive(value);
    	setCellStyle(cell,value);
    	switch (type) {
    	case 1:
		case 2:
			Double val2 = new Double(value.toString());
    		cell.setCellValue(val2);
			break;
		case 3:
			Boolean val3 = (Boolean) value;
    		cell.setCellValue(val3);
			break;
		case 4:
			Date val4 = (Date) value;
    		cell.setCellValue(val4);
			break;
		case 5:
			String val5 = value.toString();
    		cell.setCellValue(val5);
			break;
		}
    }
    
    private void setCellStyle(Cell cell,Object value){
    	CellEntity cellEntry = get(cell.getColumnIndex()).getValue();
    	CellStyle cellStyle = cellEntry.getCellStyle();
    	
    	if(cellEntry.getInitCallStyle() != null){
    		CellStyle newCellStyle = null;
			try {
				newCellStyle = workbook.createCellStyle();  
				PropertyUtils.copyProperties(newCellStyle, cellStyle);
			} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
				e.printStackTrace();
			}
			if(newCellStyle != null){
				newCellStyle = cellEntry.getInitCallStyle().setCallStyle(value, newCellStyle);
				if(newCellStyle != null){
					cellStyle = newCellStyle;
				}
			}
    	}
    	cell.setCellStyle(cellStyle);
    }

    
    /**
     * @return 0.其他类型；1.基本类型；2.数字类型3.时间类型，4其他类型（转成字符串）
     */
    public static int isPrimitive(Object obj){
    	int flag = 0;
    	if(obj != null){
    		if(obj.getClass().isPrimitive()) {
        		flag = 1;
    		}else if(obj instanceof Integer 
        	   || obj instanceof Long
        	   || obj instanceof Byte 
        	   || obj instanceof Short 
        	   || obj instanceof Float 
        	   || obj instanceof Double
        	   || obj instanceof BigDecimal
        	){
        		flag = 2;
        	}else if( obj instanceof Boolean){
        		flag = 3;
        	}else if( obj instanceof Date){
        		flag = 4;
        	}else{
        		flag = 5;
        	}
    	}
    	return flag;
    }
    
    class MethodEntry implements Entry<String,CellEntity>{
    	/** 属性名*/
    	String field;
    	/** 属性描述*/
    	CellEntity cellEntry;
		/**
		 * @param field   属性名
		 * @param desc    属性描述
		 */
		public MethodEntry(String field, CellEntity cellEntry){
			this.field = field;
			this.cellEntry = cellEntry;
		}
		
		@Override
		public String getKey() {
			return field;
		}
		@Override
		public CellEntity getValue() {
			return cellEntry;
		}
		@Override
		public CellEntity setValue(CellEntity cellEntry) {
			this.cellEntry = cellEntry;
			return cellEntry;
		}
    }

	public short getHeight() {
		return height;
	}

	public void setHeight(short height) {
		this.height = height;
	}

	public String getDateFormat() {
		return dateFormat;
	}

	public void setDateFormat(String dateFormat) {
		this.dateFormat = dateFormat;
	}

	public short getWidth() {
		return width;
	}

	public void setWidth(short width) {
		this.width = width;
	}
	
	public Workbook getWorkbook() {
		return workbook;
	}

	public void setWorkbook(Workbook workbook) {
		this.workbook = workbook;
	}

	public List<?> getData() {
		return data;
	}

	public void setData(List<?> data) {
		this.data = data;
	}

	@Override  
    public SheetEntity clone() {  
	 SheetEntity sheetEneity = (SheetEntity)super.clone();  
        return sheetEneity;  
    }
}
